﻿var spa = spa || {};

spa.dataView = function (dataSet, query) {
    /// <summary>
    /// Creates a DataView to contain DataSets
    /// </summary>
    /// <param name="dataSet" type="spa.dataSet">
    /// Required: DataSet which tracks the entities 
    /// </param>
    /// <param name="query" type="spa.odataQuery">
    /// Optional: Query for new dataView (creates blank one if omitted)
    /// </param>
    /// <return>
    /// new DataView
    /// </return>
    this.DataSet = dataSet;
    this.Query = query || new spa.odataQuery();
    this.ViewItems = ko.observableArray();
};

spa.dataView.prototype = {
    AddItem: function (newItem) {
        /// <summary>
        /// Adds a New Item to the View (auto-commit is set in Dataset)
        /// </summary>
        /// <param name="newItem" type="spa.dataEntity">
        /// Required: The New Item
        /// </param>
        newItem.EntityState(spa.entityStates.added);
        this.DataSet.Attach(newItem);
        this.ViewItems.push(newItem);
    },
    DeleteItem: function (toDelete) {
        /// <summary>
        /// Deletes an Item from the View (auto-commit is set in Dataset)
        /// </summary>
        /// <param name="toDelete" type="spa.dataEntity">
        /// Required: The Item to Delete
        /// </param>
        toDelete.EntityState(spa.entityStates.removed);
        this.ViewItems.remove(toDelete);
    },
    SaveAll: function () {
        /// <summary>
        /// Commits all Changes (if based on DataSet with Buffer = true)
        /// </summary>
        this.DataSet.SaveAll();
    },
    Refresh: function (overwrite) {
        /// <summary>
        /// Update the DataView by re-submitting the Query (
        /// </summary>
        /// <param name="overwrite" type="Boolean">
        /// Optional: Should the Query refresh entities (false to preseve changes)
        /// </param>
        this.DataSet.Read(this.ViewItems, this.Query, overwrite);
    },
};

spa.filterTypes = {
    Equal: "eq",
    NotEqual: "ne",
    GreaterThan: "gt",
    GreaterThanOrEqual: "ge",
    LessThan: "lt",
    LessThanOrEqual: "le",
    And: "and",
    Or: "or",
    Not: "not"
};

spa.ordering = function (field, ascending) {
    this.field = ko.observable(field);
    this.ascending = ascending || true;
}

spa.ordering.prototype = {
    ToOrderString: function () {
        /// <summary>
        /// Creates a String acceptable for odata Query String $orderby
        /// </summary>
        if (this.ascending) {
            return ko.utils.unwrapObservable(this.field) + " asc";
        }
        else {
            return ko.utils.unwrapObservable(this.field) + " desc";
        }
    }
};

spa.odataQuery = function () {
    this.pageNum = ko.observable(0);
    this.pageSize = ko.observable(0);
    this.orderby = ko.observableArray();
    this.filter = undefined;
};

spa.odataQuery.prototype = {
    ToQueryString: function () {
        /// <summary>
        /// Creates an odata Query string (includes $filter, $skip, $top, $orderby)
        /// </summary>
        if ((this.pageNum() != 0 || this.pageSize() != 0) && this.orderby.length > 0) {
            throw "You must specify atleast 1 order function when using paging";
        }
        if (this.pageNum() != 0 && this.pageSize() == 0) {
            throw "You cannot specify a page number without a page size";
        }
        var qstring = [];
        if (this.filter) {
            qstring.push("$filter=" + this.filter);
        }
        if (this.pageNum()) {
            qstring.push("$skip=" + (this.pageSize() * this.pageNum()));
        }
        if (this.pageSize()) {
            qstring.push("$top=" + this.pageSize());
        }
        var orders = [];
        for (var ord in this.orderby()) {
            orders.push(this.orderby()[ord].ToOrderString());
        }
        if (orders.length) {
            qstring.push("$orderby=" + orders.join(", "));
        }
        return qstring.join("&");
    }
};